﻿using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Collections.Generic;
using System.IO;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Linq;
using System.Globalization;
using XmWinKit.Common;

namespace XmWinKit.Models
{
    public class ChinaCalendarModel : INotifyPropertyChanged
    {
        // 农历月份名称
        private static readonly string[] MonthNames = { "正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "冬", "腊" };
        
        // 天干
        private static readonly string[] GanArr = { "甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸" };
        
        // 地支
        private static readonly string[] ZhiArr = { "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥" };
        
        // 生肖
        private static readonly string[] Zodiacs = { "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗", "猪" };
        
        // 农历日期名称
        private static readonly string[] DayNames = { 
            "初一", "初二", "初三", "初四", "初五", "初六", "初七", "初八", "初九", "初十",
            "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十",
            "廿一", "廿二", "廿三", "廿四", "廿五", "廿六", "廿七", "廿八", "廿九", "三十" 
        };

        private static readonly string[] ChineseNumbers = { "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九" };

        private int _selectedYear;
        private int _selectedMonth;
        private int _lastSelectedDay = 1; // 默认1号
        private Dictionary<int, List<HolidayInfo>> holidayDict = new Dictionary<int, List<HolidayInfo>>();
        private HashSet<int> loadingYears = new HashSet<int>(); // 防止重复加载

        // 缓存相关
        private const int MAX_CACHE_MONTHS = 50;
        private Dictionary<string, List<CalendarDay>> _calendarCache = new Dictionary<string, List<CalendarDay>>();
        private Queue<string> _cacheKeys = new Queue<string>(); // 用于记录缓存顺序

        private CalendarDay _selectedDay;
        public CalendarDay SelectedDay
        {
            get => _selectedDay;
            set
            {
                if (_selectedDay != value)
                {
                    _selectedDay = value;
                    OnPropertyChanged(nameof(SelectedDay));
                    OnPropertyChanged(nameof(SelectedDateText));
                    OnPropertyChanged(nameof(SelectedLunarDateText));
                    OnPropertyChanged(nameof(SelectedGanZhiText));
                }
            }
        }

        public string SelectedDateText
        {
            get
            {
                if (_selectedDay == null) return "";
                return _selectedDay.Date.ToString("yyyy-MM-dd");
            }
        }

        public string SelectedLunarDateText
        {
            get
            {
                if (_selectedDay == null) return "";
                string yearText = $"{ConvertToChineseNumber(_selectedDay.LunarYear)}年";
                string monthText = MonthNames[_selectedDay.LunarMonth - 1];
                if (_selectedDay.IsLeapMonth)
                {
                    monthText = "闰" + monthText;
                }
                string dayText = DayNames[_selectedDay.LunarDay - 1];
                return $"农历：{yearText}{monthText}月{dayText}";
            }
        }

        public string SelectedGanZhiText
        {
            get
            {
                if (_selectedDay == null) return "";
                return $"{_selectedDay.LunarYearGan}{_selectedDay.LunarYearZhi}年 {_selectedDay.Zodiac}";
            }
        }

        public ObservableCollection<int> Years { get; }
        public ObservableCollection<int> Months { get; }
        public ObservableCollection<CalendarDay> CalendarDays { get; }

        public int SelectedYear
        {
            get => _selectedYear;
            set
            {
                if (_selectedYear != value)
                {
                    _selectedYear = value;
                    OnPropertyChanged(nameof(SelectedYear));
                    OnPropertyChanged(nameof(CurrentMonthText));
                    LoadHolidayDataAsync(_selectedYear);
                    GenerateCalendar();
                }
            }
        }

        public int SelectedMonth
        {
            get => _selectedMonth;
            set
            {
                if (_selectedMonth != value)
                {
                    _selectedMonth = value;
                    OnPropertyChanged(nameof(SelectedMonth));
                    OnPropertyChanged(nameof(CurrentMonthText));
                    GenerateCalendar();
                }
            }
        }

        public string CurrentMonthText => $"{SelectedYear}-{SelectedMonth:D2}";

        public string CurrentDateText
        {
            get
            {
                var today = DateTime.Today;
                // 获取农历信息
                var calendar = new ChineseLunisolarCalendar();
                int lunarYear = calendar.GetYear(today);
                int lunarMonth = calendar.GetMonth(today);
                int lunarDay = calendar.GetDayOfMonth(today);

                // 农历月日文本
                string lunarMonthText = (lunarMonth >= 1 && lunarMonth <= 12) ? MonthNames[lunarMonth - 1] : lunarMonth.ToString();
                string lunarDayText = GetLunarDayText(lunarDay);

                // 星期
                string[] weekDays = { "日", "一", "二", "三", "四", "五", "六" };
                string weekDay = weekDays[(int)today.DayOfWeek];

                // 格式：2024.6.7 周五 六月初二 
                return $"{today:yyyy-MM-dd} 周{weekDay} {lunarMonthText}月{lunarDayText}"; 
            }
        }

        public string GanZhiYearText
        {
            get
            {
                var today = DateTime.Today;
                var calendar = new ChineseLunisolarCalendar();
                int sexagenaryYear = calendar.GetSexagenaryYear(today);
                int gan = calendar.GetCelestialStem(sexagenaryYear);
                int zhi = calendar.GetTerrestrialBranch(sexagenaryYear);
                return $"{GanArr[gan - 1]}{ZhiArr[zhi - 1]}年";
            }
        }

        public string ZodiacText
        {
            get
            {
                var today = DateTime.Today;
                var calendar = new ChineseLunisolarCalendar();
                int sexagenaryYear = calendar.GetSexagenaryYear(today);
                int zhi = calendar.GetTerrestrialBranch(sexagenaryYear);
                return $"{Zodiacs[zhi - 1]}";
            }
        }

        public ChinaCalendarModel()
        {
            Years = new ObservableCollection<int>(Enumerable.Range(1900, 200));
            Months = new ObservableCollection<int>(Enumerable.Range(1, 12));
            CalendarDays = new ObservableCollection<CalendarDay>();

            var now = DateTime.Now;
            _selectedYear = now.Year;
            _selectedMonth = now.Month;
            _lastSelectedDay = now.Day;

            // 只加载今年
            LoadHolidayDataAsync(_selectedYear);

            GenerateCalendar();
        }

        private async void LoadHolidayDataAsync(int year)
        {
            try
            {
                int thisYear = DateTime.Now.Year;
                if (year < thisYear - 10 || year > thisYear) return;
                if (holidayDict.ContainsKey(year) || loadingYears.Contains(year)) return;

                loadingYears.Add(year);

                string configDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config");
                if (!Directory.Exists(configDir))
                    Directory.CreateDirectory(configDir);

                string localPath = Path.Combine(configDir, $"holiday-{year}.json");
                List<HolidayInfo> holidays = null;

                // 1. 先尝试本地读取
                if (File.Exists(localPath))
                {
                    try
                    {
                        var json = File.ReadAllText(localPath, System.Text.Encoding.UTF8);
                        holidays = ParseHolidayJson(json);
                    }
                    catch { holidays = null; }
                }

                // 2. 本地没有就远程拉取
                if (holidays == null)
                {
                    try
                    {
                        string url = $"https://unpkg.com/holiday-calendar/data/CN/{year}.json";
                        using (var client = new WebClient())
                        {
                            client.Headers.Add("User-Agent", "Mozilla/5.0");
                            client.Encoding = System.Text.Encoding.UTF8;
                            var json = await client.DownloadStringTaskAsync(url);
                            System.Diagnostics.Debug.WriteLine($"获取的JSON: {json.Substring(0, Math.Min(100, json.Length))}...");
                            holidays = ParseHolidayJson(json);
                            // 保存到本地
                            File.WriteAllText(localPath, json, System.Text.Encoding.UTF8);
                        }
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine($"获取节假日失败: {ex.Message}");
                        holidays = new List<HolidayInfo>();
                    }
                }

                holidayDict[year] = holidays ?? new List<HolidayInfo>();
                loadingYears.Remove(year);

                // 如果当前显示的就是这个年份，刷新日历
                if (year == SelectedYear)
                {
                    // 在UI线程刷新
                    Application.Current.Dispatcher.Invoke(() => {
                        GenerateCalendar();
                    });
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"节假日处理异常: {ex.Message}");
            }
        }

        // 解析API返回的json
        private List<HolidayInfo> ParseHolidayJson(string json)
        {
            try
            {
                // 预处理 JSON 字符串
                json = json.Replace("\n", "").Replace("\r", "");
                
                // 使用 JObject 更灵活地解析
                var jObj = JObject.Parse(json);
                var dates = jObj["dates"] as JArray;
                
                if (dates == null || !dates.Any())
                    return new List<HolidayInfo>();
                    
                var result = new List<HolidayInfo>();
                
                foreach (var item in dates)
                {
                    try
                    {
                        var dateStr = item["date"]?.ToString();
                        var type = item["type"]?.ToString();
                        
                        if (string.IsNullOrEmpty(dateStr) || string.IsNullOrEmpty(type))
                            continue;
                            
                        string name = null;
                        // 尝试多种字段获取名称
                        name = item["name_cn"]?.ToString();
                        if (string.IsNullOrEmpty(name))
                            name = item["name"]?.ToString();
                        if (string.IsNullOrEmpty(name))
                            name = "未知假日";
                            
                        result.Add(new HolidayInfo
                        {
                            Date = DateTime.Parse(dateStr),
                            Name = name,
                            Type = type
                        });
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine($"解析单个节日项失败: {ex.Message}");
                        // 继续处理下一项
                        continue;
                    }
                }
                
                return result;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"解析JSON完全失败: {ex.Message}");
                return new List<HolidayInfo>();
            }
        }

        // 用于反序列化API结构
        private class HolidayApiRoot
        {
            public int year { get; set; }
            public string region { get; set; }
            public List<HolidayApiDate> dates { get; set; }
        }
        private class HolidayApiDate
        {
            public string date { get; set; }
            public string name { get; set; }
            public string name_cn { get; set; }
            public string name_en { get; set; }
            public string type { get; set; }
        }

        // 获取缓存key
        private string GetCacheKey(int year, int month)
        {
            return $"{year}-{month:D2}";
        }

        // 从缓存获取或生成日历数据
        private List<CalendarDay> GetOrCreateCalendarDays(int year, int month)
        {
            string cacheKey = GetCacheKey(year, month);
            
            // 尝试从缓存获取
            if (_calendarCache.TryGetValue(cacheKey, out var cachedDays))
            {
                return cachedDays;
            }

            // 缓存未命中，生成新的日历数据
            var days = GenerateCalendarDays(year, month);
            
            // 更新缓存
            UpdateCache(cacheKey, days);
            
            return days;
        }

        // 更新缓存
        private void UpdateCache(string key, List<CalendarDay> days)
        {
            // 如果缓存已满，删除最早的
            if (_calendarCache.Count >= MAX_CACHE_MONTHS)
            {
                var oldestKey = _cacheKeys.Dequeue();
                _calendarCache.Remove(oldestKey);
            }

            // 添加新的缓存
            _calendarCache[key] = days;
            _cacheKeys.Enqueue(key);
        }

        // 生成日历数据
        private List<CalendarDay> GenerateCalendarDays(int year, int month)
        {
            var days = new List<CalendarDay>();
            DateTime firstDayOfMonth = new DateTime(year, month, 1);
            int firstDayOfWeek = ((int)firstDayOfMonth.DayOfWeek + 6) % 7;
            int daysFromPrevMonth = firstDayOfWeek;
            DateTime lastDayOfPrevMonth = firstDayOfMonth.AddDays(-1);

            // 上月日期
            for (int i = daysFromPrevMonth - 1; i >= 0; i--)
            {
                DateTime day = lastDayOfPrevMonth.AddDays(-i);
                days.Add(CreateCalendarDay(day, false));
            }

            // 当月日期
            int daysInMonth = DateTime.DaysInMonth(year, month);
            int selectDay = Math.Min(_lastSelectedDay, daysInMonth);
            for (int i = 1; i <= daysInMonth; i++)
            {
                DateTime day = new DateTime(year, month, i);
                days.Add(CreateCalendarDay(day, true, 
                    day.Date == DateTime.Today, 
                    i == selectDay));
            }

            // 下月日期
            int remainingDays = 42 - days.Count;
            DateTime firstDayOfNextMonth = firstDayOfMonth.AddMonths(1);
            for (int i = 1; i <= remainingDays; i++)
            {
                DateTime day = firstDayOfNextMonth.AddDays(i - 1);
                days.Add(CreateCalendarDay(day, false));
            }

            // 节假日信息处理
            var holidays = holidayDict.ContainsKey(year) ? holidayDict[year] : new List<HolidayInfo>();
            foreach (var day in days)
            {
                var h = holidays.FirstOrDefault(x => 
                    x.Date.Year == day.Date.Year && 
                    x.Date.Month == day.Date.Month && 
                    x.Date.Day == day.Date.Day);
                if (h != null)
                {
                    if (h.Type == "public_holiday")
                    {
                        day.IsRest = true;
                        day.HolidayName = h.Name;
                    }
                    else if (h.Type == "transfer_workday")
                    {
                        day.IsWork = true;
                        day.HolidayName = h.Name;
                    }
                }
            }

            return days;
        }

        // 修改原有的 GenerateCalendar 方法
        private void GenerateCalendar()
        {
            CalendarDays.Clear();
            var days = GetOrCreateCalendarDays(SelectedYear, SelectedMonth);
            foreach (var day in days)
            {
                CalendarDays.Add(day);
            }
        }

        // 根据日期创建 CalendarDay 对象
        private CalendarDay CreateCalendarDay(DateTime day, bool isCurrentMonth, bool isToday = false, bool isSelected = false)
        {
            var calendar = new ChineseLunisolarCalendar();

            int lunarYear = calendar.GetYear(day);
            int lunarMonth = calendar.GetMonth(day);
            int lunarDay = calendar.GetDayOfMonth(day);
            bool isLeapMonth = calendar.IsLeapMonth(lunarYear, lunarMonth);

            // 调整闰月显示
            if (isLeapMonth)
            {
                // 如果是闰月，月份需要减1
                lunarMonth--;
            }

            int sexagenaryYear = calendar.GetSexagenaryYear(day);
            int yearStem = calendar.GetCelestialStem(sexagenaryYear);
            int yearBranch = calendar.GetTerrestrialBranch(sexagenaryYear);

            // 1. 先判断阳历节日
            string showLunarDay = "";
            string showLunarDayColor = "";
            int md = day.Month * 100 + day.Day;
            switch (md)
            {
                case 101: showLunarDay = "元旦"; break;
                case 214: showLunarDay = "情人节"; break;
                case 308: showLunarDay = "妇女节"; break;
                case 312: showLunarDay = "植树节"; break;
                case 401: showLunarDay = "愚人节"; break;
                case 501: showLunarDay = "劳动节"; break;
                case 504: showLunarDay = "青年节"; break;
                case 601: showLunarDay = "儿童节"; break;
                case 701: showLunarDay = "建党节"; break;
                case 801: showLunarDay = "建军节"; break;
                case 910: showLunarDay = "教师节"; break;
                case 1001: showLunarDay = "国庆节"; break;
                case 1031: showLunarDay = "万圣节"; break;
                case 1111: showLunarDay = "光棍节"; break;
                case 1224: showLunarDay = "平安夜"; break;
                case 1225: showLunarDay = "圣诞节"; break;
            }
            if(!string.IsNullOrEmpty(showLunarDay)){
                showLunarDayColor = "#FFB84D";
            }

            // 2. 判断农历节日
            if (string.IsNullOrEmpty(showLunarDay))
            {
                // 除夕：农历十二月最后一天
                if (lunarMonth == 12 && lunarDay == calendar.GetDaysInMonth(lunarYear, 12))
                {
                    showLunarDay = "除夕";
                    showLunarDayColor = "#FFB84D";
                }
                // 元宵：农历正月十五
                else if (lunarMonth == 1 && lunarDay == 15)
                {
                    showLunarDay = "元宵节";
                    showLunarDayColor = "#FFB84D";
                }
                // 端午：农历五月初五
                else if (lunarMonth == 5 && lunarDay == 5)
                {
                    showLunarDay = "端午节";
                    showLunarDayColor = "#FFB84D";
                }
                // 中元：农历七月十五
                else if (lunarMonth == 7 && lunarDay == 15)
                {
                    showLunarDay = "中元节";
                    showLunarDayColor = "#FFB84D";
                }
                // 中秋：农历八月十五
                else if (lunarMonth == 8 && lunarDay == 15)
                {
                    showLunarDay = "中秋节";
                    showLunarDayColor = "#FFB84D";
                }
                // 重阳：农历九月初九
                else if (lunarMonth == 9 && lunarDay == 9)
                {
                    showLunarDay = "重阳节";
                    showLunarDayColor = "#FFB84D";
                }
                // 腊八：农历十二月初八
                else if (lunarMonth == 12 && lunarDay == 8)
                {
                    showLunarDay = "腊八";
                    showLunarDayColor = "#FFB84D";
                }
            }

            // 3. 判断节气（此处 SolarTerm 为空，后续可补充）
            string solarTerm = SolarTermHelper.GetSolarTerm(day);
            if (string.IsNullOrEmpty(showLunarDay) && !string.IsNullOrEmpty(solarTerm))
            {
                showLunarDay = solarTerm;
                showLunarDayColor = "#4DD0E1"; // 青绿色
            }

            // 4. 默认农历日文本
            if (string.IsNullOrEmpty(showLunarDay))
            {
                if (lunarDay == 1)
                {
                    string monthText = (lunarMonth >= 1 && lunarMonth <= 12) ? MonthNames[lunarMonth - 1] : lunarMonth.ToString();
                    if (isLeapMonth)
                        showLunarDay = $"闰{monthText}月";
                    else
                        showLunarDay = $"{monthText}月";
                    showLunarDayColor = "#F06292"; // 粉色
                }
                else
                {
                    showLunarDay = GetLunarDayText(lunarDay);
                    showLunarDayColor = "#AAAAAA"; // 普通农历日
                }
            }

            return new CalendarDay
            {
                Date = day,
                DayNumber = day.Day.ToString(),
                LunarYear = lunarYear,
                LunarMonth = lunarMonth,
                LunarDay = lunarDay,
                IsLeapMonth = isLeapMonth,
                LunarYearGan = GetCelestialStemText(yearStem),
                LunarYearZhi = GetTerrestrialBranchText(yearBranch),
                LunarMonthGan = "",
                LunarMonthZhi = "",
                LunarDayGan = "",
                LunarDayZhi = "",
                Zodiac = GetZodiacText(yearBranch),
                SolarTerm = solarTerm,
                LunarDayText = GetLunarDayText(lunarDay),
                ShowLunarDay = showLunarDay,
                ShowLunarDayColor = showLunarDayColor,
                IsCurrentMonth = isCurrentMonth,
                IsToday = isToday,
                IsSelected = isSelected
            };
        }

        // 辅助方法：获取天干文字
        private string GetCelestialStemText(int stem)
        {
            return GanArr[stem - 1];
        }

        // 辅助方法：获取地支文字
        private string GetTerrestrialBranchText(int branch)
        {
            return ZhiArr[branch - 1];
        }

        // 辅助方法：获取生肖文字
        private string GetZodiacText(int branch)
        {
            return Zodiacs[branch - 1];
        }

        // 辅助方法：获取农历日显示文本
        private string GetLunarDayText(int day)
        {
            return DayNames[day - 1];
        }

        private string ConvertToChineseNumber(int number)
        {
            return string.Join("", number.ToString().Select(c => ChineseNumbers[c - '0']));
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

        // 在外部（如窗口点击事件）选中某天时，记得同步 _lastSelectedDay
        public void SelectDay(CalendarDay day)
        {
            foreach (var d in CalendarDays)
                d.IsSelected = false;
            if (day != null && day.IsCurrentMonth)
            {
                day.IsSelected = true;
                _lastSelectedDay = day.Date.Day;
                SelectedDay = day;  // 更新选中日期
            }
        }
    }

    public class CalendarDay : INotifyPropertyChanged
    {
        public DateTime Date { get; set; }
        public string DayNumber { get; set; }
        
        // 农历相关属性
        public int LunarYear { get; set; }
        public int LunarMonth { get; set; }
        public int LunarDay { get; set; }
        public bool IsLeapMonth { get; set; }
        public string LunarYearGan { get; set; }  // 天干
        public string LunarYearZhi { get; set; }  // 地支
        public string LunarMonthGan { get; set; }
        public string LunarMonthZhi { get; set; }
        public string LunarDayGan { get; set; }
        public string LunarDayZhi { get; set; }
        public string Zodiac { get; set; }        // 生肖
        public string SolarTerm { get; set; }     // 节气
        public string LunarDayText { get; set; }  // 农历日期显示文本，如"初一"、"十五"
        
        // 其他原有属性
        public bool IsCurrentMonth { get; set; }
        public bool IsRest { get; set; }
        public bool IsWork { get; set; }
        public string HolidayName { get; set; }
        
        private bool _isToday;
        public bool IsToday
        {
            get => _isToday;
            set
            {
                if (_isToday != value)
                {
                    _isToday = value;
                    OnPropertyChanged(nameof(IsToday));
                    OnPropertyChanged(nameof(TodayVisibility));
                }
            }
        }

        private bool _isSelected;
        public bool IsSelected
        {
            get => _isSelected;
            set
            {
                if (_isSelected != value)
                {
                    _isSelected = value;
                    OnPropertyChanged(nameof(IsSelected));
                    OnPropertyChanged(nameof(SelectedVisibility));
                }
            }
        }

        public string ShowLunarDay
        {
            get; set;
        }

        public string ShowLunarDayColor
        {
            get; set;
        }

        // 选中时可见
        public Visibility SelectedVisibility => IsSelected ? Visibility.Visible : Visibility.Collapsed;
        // 今天时可见
        public Visibility TodayVisibility => IsToday ? Visibility.Visible : Visibility.Collapsed;

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }

    public class HolidayInfo
    {
        public DateTime Date { get; set; }
        public string Name { get; set; }
        public string Type { get; set; } // public_holiday/transfer_workday
    }
}
